#!/usr/bin/python3
###############################################################################
'''2阶多路反馈滤波器参数求解'''
# Copyright (c) 2022 Xu Ruijun | 1687701765@qq.com
#
# This file is part of Electronic Analog Filter Design Tool(eAFDTool).
#
# eAFDTool is free software: you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free Software
# Foundation, either version 3 of the License, or any later version.
#
# eAFDTool is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
# A PARTICULAR PURPOSE. See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along with
# eAFDTool. If not, see <https://www.gnu.org/licenses/>.
###############################################################################
import math
from .basic_solver import RC_filter

__author__ = "Xu Ruijun"
__copyright__ = "Copyright (c) 2022 Xu Ruijun"
__license__ = "GPLv3 or later"


class MFb_LPF2(RC_filter):
    rx    = [0, 1, 2]
    cx    = [3, 4]
    rcn   = ['r1', 'r2', 'r3', 'c1', 'c2']
    t2rc  = [[0, 3], [1, 4], [2, 4]]
    tname = ['R1C1', 'R2C2', 'R3C2']
    tchr  = ['x',    'y',    'u'   ]
    krat  = [2, 0]  # k = r3/r1

    def t_adj(self, **kwargs):
        k = self.G
        a, b = self.A[:2]
        ivars = self.process_relat_vars(kwargs, 'xyu')
        assert ivars.count(None) == 2
        x, y, u = ivars
        if u is not None:
            y = (b - u)/(1 + k)
        if y is not None:
            x = a/(k*y)
        if y is None:
            y = a/(k*x)
        if u is None:
            u = b - (1 + k)*y
        t = [x, y, u]
        assert t.count(None) == 0
        self.t = t
        return t

    def initv(self):
        k = self.G
        a, b = self.A[:2]
        y_u = b/(2 + k)
        return self.t_adj(u=y_u)


class MFb_HPF2(RC_filter):
    rx    = [0, 1]
    cx    = [2, 3, 4]
    rcn   = ['r1', 'r2', 'c1', 'c2', 'c3']
    t2rc  = [[0, 2], [1, 3], [0, 3]]
    tname = ['R1C1', 'R2C2', 'R1C2']
    tchr  = ['x',    'y',    'u'   ]
    krat  = [2, 4] # k=c1/c3

    def t_adj(self, **kwargs):
        k = self.G
        a, b = self.A[:2]
        ivars = self.process_relat_vars(kwargs, 'xyu')
        assert ivars.count(None) == 2
        x, y, u = ivars
        if u is not None:
            x = (b - u)/(1 + k)
        if x is not None:
            y = a*k/x
        if x is None:
            x = s*k/y
        if u is None:
            u = b - (1 + k)*x
        t = [x, y, u]
        assert t.count(None) == 0
        self.t = t
        return t

    def initv(self):
        k = self.G
        a, b = self.A[:2]
        x_u = b/(2 + 1/k)
        return self.t_adj(u=x_u)


class MFb_BPF2(RC_filter):
    rx   = [0, 1, 2]
    cx   = [3, 4]
    rcn  = ['r1', 'r2', 'r3', 'c1', 'c2']
    t2rc = [[0, 3], [1, 4], [2, 3], [2, 4]]
    tname= ['R1C1', 'R2C2', 'R3C1', 'R3C2']
    tchr = ['x',    'y',    'u',    'v',  ]
    # TODO: 待修复：UI调节R1C1光标会向下漂移，需要禁止调节
    # 修复前请不要调节UI上的对应进度条

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.format_A0()

    def t_adj(self, **kwargs):
        ivars = self.process_relat_vars(kwargs, 'yuv')
        assert ivars.count(None) == 2
        b, c = self.A[1:]
        x = 1/self.B[0]
        y, u, v = ivars
        if u is not None:
            v = 1/(b - 1/u)
        elif v is not None:
            u = 1/(b - 1/v)
        # u, v
        if y is None:
            y = 1/(c - 1/(x*v))/u
        else:
            # X=1/x, Y=1/y, u=1/U, v=1/V
            #  V +  U = b
            # XV + YU = c
            # solve V, U
            X = 1/x
            Y = 1/y
            v = (Y-X)/(b*Y - c)
            u = (Y-X)/(c - b*X)
        t = [x, y, u, v]
        assert t.count(None) == 0
        self.t = t
        return t

    def initv(self):
        #     |b 1|     |1 b|
        #     |c Y|     |X c|
        # V = ----- U = -----
        #     |1 1|     |1 1|
        #     |X Y|     |X Y|
        # 为了保证U为正数，Y-X与c-b*X必须同号
        # 为了保证V为正数，Y-X与c-b*Y必须同号
        b, c = self.A[1:]
        X = self.B[0]
        delta = c - b*X
        if delta > 0:   # Y-X>0, c-b*Y>0
            Y = max(X, c/b)*1.6
        elif delta < 0: # Y-X<0, c-b*Y<0
            Y = min(X, c/b)*0.6
        else:
            raise ValueError(f'c - b*X == {delta}')
        # 为了防止程序出错，这里不断言Y为正数
        y = 1/Y
        return self.t_adj(y=y)
